# 导入rest_f 使用serialzers
from rest_framework import serializers

# 创建序列化器serializers.ModelSerializer
from users.models import Users, Address
import re
import logging
from django_redis import get_redis_connection

from .utils import generate_save_user_token_url
from celery_tasks.email.tasks import send_verify_email


class CreateUserSerializer(serializers.ModelSerializer):
    # 声明 【序列化和反序列化】 字段
    password2 = serializers.CharField(label="确认密码", write_only=True)
    sms_code = serializers.CharField(label="短信验证码", write_only=True)
    allow = serializers.CharField(label="确认协议", write_only=True)
    token = serializers.CharField(label="jwt token", read_only=True)

    class Meta:
        # 关联模型化对象
        model = Users
        fields = ["token", "id", "username", "password", "password2", "sms_code", "allow", "mobile"]
        extra_kwargs = {"username":
            {
                'min_length': 5,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅允许5-20个字符的用户名',
                    'max_length': '仅允许5-20个字符的用户名',
                }
            },
            "password": {
                'write_only': True,
                'min_length': 8,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅允许8-20个字符的密码',
                    'max_length': '仅允许8-20个字符的密码',
                }
            }
        }
        # 校验方法 validate 和 validate_字段名

    def validate_allow(self, value):
        """用户协议"""
        if value != "true":
            raise serializers.ValidationError("请同意用户协议")

        # 原样返回
        return value

    def validate_mobile(self, value):
        """手机格式"""
        if not re.match(r'^1[3-9]\d{9}$', value):
            raise serializers.ValidationError("手机格式不正确")
        # 校验手机唯一性
        count = Users.objects.filter(mobile=value).count()
        if count > 0:
            raise serializers.ValidationError("该手机以注册")

        # 原样返回
        return value

    def validate_username(self, value):
        """校验用户唯一性"""
        count = Users.objects.filter(username=value).count()

        if count > 0:
            raise serializers.ValidationError("该用户以注册")

        return value

    # 校验方法 【validate】 对多个字段进行比较
    def validate(self, attrs):
        """
        :param attrs:获取用户多字段
        :return:
        """
        # 判断用户密码
        password = attrs.get("password")
        password2 = attrs.get("password2")

        if password != password2:
            raise serializers.ValidationError("密码不在一直")

        # 判断用户短信验证
        # 获取字段参数
        # 操作redis数据库
        # 获取属性

        sms_code = attrs.get("sms_code")
        mobile = attrs.get("mobile")
        redis = get_redis_connection("verify_codes")

        try:
            sms_redis = redis.get("sms_%s" % mobile)
        except Exception as e:
            logging.error(e)
            raise serializers.ValidationError("数据库获取验证码失败")
        try:
            sms_real = sms_redis.decode()
        except Exception as e:
            logging.error(e)
            raise serializers.ValidationError("解码失败")

        if sms_code != sms_real:
            raise serializers.ValidationError("验证码不正确")

        return attrs




        # 模型操作【create 和update】

    def create(self, validated_data):
        """
        检验玩成后，提交用户数据
        :param validated_data:
        :return:
        """

        # 移除模型中不存在的属性

        del validated_data["password2"]
        del validated_data["sms_code"]
        del validated_data["allow"]

        # 使用create保存数据
        # create super().create(validated_data) 实现了自动添加数据功能
        user = super().create(validated_data)

        # 通过模型设置密码加密
        user.set_password(validated_data["password"])

        user.save()

        # 注册成功使用jwt保存登陆状态
        from rest_framework_jwt.settings import api_settings

        # 获取生成载荷函数

        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER

        # 获取 生成token的函数
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)

        user.token = token

        # 返回模型
        return user


class EmaileSerializer(serializers.ModelSerializer):
    """邮箱序列化器"""

    class Meta:
        model = Users
        # 设置验证字段信息
        fields = ["id", "email"]

        # 添加字段校验属性
        extra_kwargs = {
            "email": {
                "required": True
            }
        }

    # 调用update方法更新状态
    def update(self, instance, validated_data):
        # 校验/设置用户邮箱保存用户邮箱
        instance.email = validated_data["email"]
        # 保存用户哟想
        instance.save()

        # 生成邮箱的链接【insance 就是当前已登陆的一年过户】
        verify_url = generate_save_user_token_url(instance)

        # 使用异步发送链接给用户
        send_verify_email.delay(instance.email, verify_url)

        return instance


class UserAddressSerializer(serializers.ModelSerializer):
    """
    用户地址序列化器
    """
    province = serializers.StringRelatedField(read_only=True)
    city = serializers.StringRelatedField(read_only=True)
    district = serializers.StringRelatedField(read_only=True)
    province_id = serializers.IntegerField(label='省ID', required=True)
    city_id = serializers.IntegerField(label='市ID', required=True)
    district_id = serializers.IntegerField(label='区ID', required=True)

    class Meta:
        model = Address
        exclude = ('user', 'is_deleted', 'create_time', 'update_time')

    def validate_mobile(self, value):
        """
        验证手机号
        """
        if not re.match(r'^1[3-9]\d{9}$', value):
            raise serializers.ValidationError('手机号格式错误')
        return value

    def create(self, validated_data):
        """
        保存
        """
        validated_data['user'] = self.context['request'].user
        return super().create(validated_data)


class AddressTitleSerializer(serializers.ModelSerializer):
    """
    地址标题
    """

    class Meta:
        model = Address
        fields = ('title',)
